(define (clear! cell)
    (set-car! cell #f))

(define (test-and-set! cell)
    (if (car cell)
        #t
        (begin (set-car! cell #t)
               #f)))

(define (make-mutex)
    (let ((cell (list #f)))
        (define (the-mutex m)
            (cond ((eq? m 'acquire)
                   (if (test-and-set! cell)
                       (the-mutex 'acquire)))
                  ((eq? m 'release) (clear! cell))))
        the-mutex))

(define (make-serializer)
    (let ((mutex (make-mutex)))
        (lambda (p)
            (define (serialized-p . args)
                (mutex 'acquire)
                (let ((val (apply p args)))
                    (mutex 'release)
                    val))
            serialized-p)))

; a)基于互斥元
(define (make-semaphore1 n)
    (let ((mutex (make-mutex)))
        (define (semaphore m)
            (cond ((eq? m 'acquire)
                   (mutex 'acquire)
                   (if (> n 0)
                       (begin (set! n (- n 1))
                              (mutex 'release)
                              'ok)
                       (begin (mutex 'release)
                              (semaphore 'acquire))))
                  ((eq? m 'release)
                   (mutex 'acquire)
                   (set! n (+ n 1))
                   (mutex 'release)
                   'ok)))
        semaphore))
;测试
; (define s1 (make-semaphore1 3))
; (s1 'acquire)
; (s1 'acquire)
; (s1 'acquire)
; (s1 'release)
; (s1 'acquire)

; b) 基于原子的test-and-set!操作
(define (make-semaphore2 n)
    (let ((cell (list #f)))
        (define (the-semaphore m)
            (cond ((eq? m 'acquire)
                   (if (test-and-set! cell)
                       (the-semaphore 'acquire))
                   (if (> n 0)
                       (begin (set! n (- n 1))
                              (clear! cell)
                              'ok)
                       (begin (clear! cell)
                              (the-semaphore 'acquire))))
                  ((eq? m 'release)
                   (if (test-and-set! cell)
                       (the-semaphore 'release))
                   (set! n (+ n 1))
                   (clear! cell)
                   'ok)))
        the-semaphore))

; (define s2 (make-semaphore2 3))
; (s2 'acquire)
; (s2 'acquire)
; (s2 'acquire)
; (s2 'release)
; (s2 'acquire)